package com.bosssoft.trainee.nontax.service.jwt;

import com.bosssoft.trainee.nontax.service.RoleService;
import com.bosssoft.trainee.nontax.entity.dto.UserDto;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Service;

import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.*;

/**
 * @Description: token service interface
 * @Author: Luo WenLong
 * @Date: 2022/6/26 13:50
 */
@Slf4j
@ConfigurationProperties(prefix = "config.jwt")
@Service
public class TokenServiceImpl implements TokenService {

    @Autowired
    RoleService roleService;

    private final String secret = "vueAdmin";

    // 设置过期时间 10小时
    private final long ttlMillis = 36000000;

    // user_roles
    private final String userRoleKey = "user_roles";

    /**
     * @Description: token获取工具
     * @param user 待制作token的user
     * @return: java.lang.String
     * @Author: Luo WenLong
     * @Date: 2022/6/26 14:02
     */
    @Override
    public String getToken(UserDto user) {
        log.info("getToken by user: " + user.toString());

        // 签名方法 HS256
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 生成Jwt的时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        // 生成秘钥
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(secret);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        // 获取用户的角色信息
        List<String> roles = new ArrayList<>();
        roleService.getRolesByUserId(user.getUserId()).forEach(role ->
                roles.add(role.getRoleName()));

        // 配置参数
        Map<String,Object> map = new TreeMap<>();
        map.put(userRoleKey, roles);
        map.put("user_id", user.getUserId());
        map.put("jti", user.getUserId());

        // 设置JWT所存储的信息
        JwtBuilder builder = Jwts.
                builder().
                setId(String.valueOf(user.getUserId())).
                setIssuedAt(now).
                setClaims(map).
                signWith(signatureAlgorithm, signingKey);

        // 设置过期时间
        long expMillis = nowMillis + ttlMillis;
        Date exp = new Date(expMillis);
        builder.setExpiration(exp);

        // 构建JWT并将其序列化为紧凑的URL安全字符串
        return builder.compact();
    }

    /**
     * @Description: 从token获取用户id
     * @param token jwt token
     * @return: java.lang.Integer
     * @Author: Luo WenLong
     * @Date: 2022/6/26 14:01
     */
    @Override
    public Integer getUserIdFromToken(String token) {
        Integer userId = null;
        try{
            Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary("vueAdmin")).parseClaimsJws(token).getBody();
            userId = (Integer) claims.get("jti");
        }catch (Exception e){
            log.info("token error, cant get userId form this token: " + token);
        }
        return userId;
    }


    /**
     * @Description: 从request中获取用户id
     * @param httpServletRequest request
     * @return: java.lang.Integer
     * @Author: Luo WenLong
     * @Date: 2022/6/26 13:55
     */
    @Override
    public Integer getUserIdFromRequest(HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        if (token == null) {
            token = httpServletRequest.getHeader("X-Token");
        }
        if (token == null) {
            throw new RuntimeException("can't get token");
        }
        int userId;
        Claims claims = Jwts.
                parser().
                setSigningKey(DatatypeConverter.parseBase64Binary(secret)).
                parseClaimsJws(token).getBody();
        userId = Integer.parseInt((String) claims.get("jti"));
        return userId;
    }

    /**
     * @Description: 从token中获取角色权限信息
     * @param token token
     * @return: java.util.ArrayList<java.lang.String>
     * @Author: Luo WenLong
     * @Date: 2022/6/26 13:54
     */
    @Override
    public List<String> getUserRolesFormToken(String token) {
        Claims claims = Jwts.
                parser().
                setSigningKey(DatatypeConverter.parseBase64Binary(secret)).
                parseClaimsJws(token).getBody();
        return claims.get(userRoleKey) == null ? null: (List<String>) claims.get(userRoleKey);
    }
}
